import { app } from "../../../base";
import { Injector } from "../../base/utils/Injector";


export interface IStorage {
    setValue(key: string, value: string | number | boolean | null | undefined): void;
    getValue(key: string): string;
    removeValue(key: string): void;
    clear(): void;
}

enum StorageCommonKey {
    DEFAULT_USERID_KEY = "DEFAULT_USERID_KEY",
    EFFECTS_VOLUME_KEY = "EFFECTS_VOLUME_KEY",
    MUSIC_VOLUME_KEY = "MUSIC_VOLUME_KEY",
    LOGIN_DAYS_KEY = "LOGIN_DAYS_KEY",
    LAST_LOGIN_TIME = "LAST_LOGIN_TIME",
}

/**
 * 本地持久化工具
 * 1. 区分全局和用户数据
 * 2. 数据缓存，减少io
 */
export class Storage {
    static KEY: string = "Storage";
    private static created: boolean = false;
    private _cacheEnable: boolean = false;
    private _cacheCD: number = 0;
    private _cacheStore: Map<string, { value: string | boolean, dirty: boolean }> = new Map();
    constructor() {
        if (Storage.created) {
            throw new Error("StorageUtils 是单例");
        }
        Storage.created = true;

    }

    /**
     * 设置缓存策略
     * @param enable 是否高速缓存
     * @param cd 缓存cd, 单位毫秒, 默认为30秒(30000)
     * @returns 
     */
    public setCache(enable: boolean, cd: number = 30000): void {
        if (this._cacheEnable == enable) {
            return;
        }

        app.App.offHide(this._flushCache, this);
        app.timer.clear(this, this._flushCache);
        if (enable) {
            app.App.onHide(this._flushCache, this);
            if (this._cacheCD != cd) {
                app.timer.loop(cd, this, this._flushCache);
            }
        } else {
            this._cleanCache();
        }
        this._cacheEnable = enable;
    }

    private _userId: string;
    /**
     * 当前用户ID
     */
    set userId(userId: string) {
        this._userId = userId;
        this.setGValue(StorageCommonKey.DEFAULT_USERID_KEY, this._userId);
        let lastLoginTime = this.getUValue(StorageCommonKey.LAST_LOGIN_TIME, 0);
        if (Math.floor(lastLoginTime / (24 * 60 * 60 * 1000)) != Math.floor(Date.now() / (24 * 60 * 60 * 1000))) {
            this.setUValue(StorageCommonKey.LOGIN_DAYS_KEY, this.loginDays + 1);
        }
        this.setUValue(StorageCommonKey.LAST_LOGIN_TIME, Date.now());
    }

    /**
     * 当前用户ID
     */
    get userId(): string {
        if (!this._userId) {
            this._userId = this.getGValue(StorageCommonKey.DEFAULT_USERID_KEY);
        }
        return this._userId;
    }

    /**
     * 获取当前用户的音效声音大小
     */
    get effectsVolume(): number {
        return this.getGValue(StorageCommonKey.EFFECTS_VOLUME_KEY, 1);
    }

    /**
     * 设置当前用户的音效声音大小
     */
    set effectsVolume(value: number) {
        this.setGValue(StorageCommonKey.EFFECTS_VOLUME_KEY, value);
    }

    /**
     * 获取当前用户的背景音乐声音大小
     */
    get musicVolume(): number {
        return this.getGValue(StorageCommonKey.MUSIC_VOLUME_KEY, 1);
    }

    /**
     * 设置当前用户的背景音乐声音大小
     */
    set musicVolume(value: number) {
        this.setGValue(StorageCommonKey.MUSIC_VOLUME_KEY, value);
    }

    /**
     * 登录天数
     */
    get loginDays(): number {
        return this.getUValue(StorageCommonKey.LOGIN_DAYS_KEY, 0);
    }

    /**
     * 最后登录时间
     */
    get lastLoginTime(): number {
        return this.getUValue(StorageCommonKey.LAST_LOGIN_TIME, 0);
    }

    /**
     * 获取当前用户的值
     * @param key 
     * @param defaultValue 
     * @returns 
     */
    getUValue<T extends string | number | boolean | null | undefined | object>(key: string, defaultValue?: T): T {
        return this._getValue<T>(this._getUserKey(key), defaultValue);
    }

    /**
     * 设置当前用户的值
     * @param key 
     * @param value 
     */
    setUValue(key: string, value: string | number | boolean | null | undefined | object): void {
        this._setValue(this._getUserKey(key), value);
    }

    /**
     * 删除当前用户的值
     * @param key 
     */
    removeUValue(key: string) {
        this._removeValue(this._getUserKey(key));
    }

    /**
     * 获取全局值
     * @param key 
     * @param defaultValue 
     * @returns 
     */
    getGValue<T extends string | number | boolean | null | undefined | object>(key: string, defaultValue?: T): T {
        return this._getValue<T>(key, defaultValue);
    }

    /**
     * 设置全局值
     * @param key 
     * @param value 
     */
    setGValue(key: string, value: string | number | boolean | null | undefined | object): void {
        this._setValue(key, value);
    }

    /**
     * 删除全局值
     * @param key 
     */
    removeGValue(key: string) {
        this._removeValue(key);
    }

    private _getUserKey(key: string): string {
        return key + this.userId;
    }

    private _setValue(key: string, value: string | number | boolean | null | undefined | object): void {
        if (null == key) {
            console.error("存储的key不能为空");
            return;
        }
        if (null == value) {
            console.warn(`存储的值为空，则直接移除该key:${key}`);
            this._removeValue(key);
            return;
        }
        if (typeof value === 'function') {
            console.error("储存的值不能为方法");
            return;
        }
        if (typeof value === 'object') {
            try {
                value = JSON.stringify(value);
            } catch (e) {
                console.error(`解析失败，str=${value}`);
                return;
            }
        } else if (typeof value === 'number') {
            value = value + "";
        }
        if (this._cacheEnable) {
            this._internalSetValue(key, value);
        } else {
            this.impl.setValue(key, value);
        }
    }

    private _internalSetValue(key: string, value: string | boolean): void {
        let cache = this._cacheStore.get(key);
        if (!cache) {
            cache = { value: this.impl.getValue(key), dirty: true };
            this._cacheStore.set(key, cache);
        } else if (cache.value != value) {
            cache.value = value;
            cache.dirty = true;
        }
    }

    private _flushCache(): void {
        this._cacheStore.forEach((cache, key) => {
            if (cache.dirty) {
                this.impl.setValue(key, cache.value);
                cache.dirty = false;
            }
        })
    }

    private _cleanCache(): void {
        this._flushCache();
        this._cacheStore.clear();
    }

    private _getValue<T extends string | number | boolean | null | undefined | object>(key: string, defaultValue: T): T {
        if (null == key) {
            console.error("存储的key不能为空");
            return;
        }
        let value: any = this._cacheEnable ? this._internalGetValue(key) : this.impl.getValue(key);
        if (null == defaultValue || typeof defaultValue === 'string') {
            return value as T;
        }
        if (null === value) {
            return defaultValue;
        }
        if (typeof defaultValue === 'number') {
            return (value == "" || isNaN(Number(value)) ? defaultValue : Number(value)) as T;
        }
        if (typeof defaultValue === 'boolean') {
            return (value === true || "true" == value || "" === value) as T; // 不要使用Boolean("false");
        }
        if (typeof defaultValue === 'object') {
            try {
                return JSON.parse(value);
            } catch (e) {
                console.error("解析数据失败,value=" + value);
                return defaultValue;
            }
        }
        return
    }

    private _internalGetValue(key: string): any {
        let cache = this._cacheStore.get(key);
        if (!cache) {
            cache = { value: this.impl.getValue(key), dirty: false };
            this._cacheStore.set(key, cache);
        }
        return cache.value;
    }

    private _removeValue(key: string) {
        if (null == key) {
            console.error("存储的key不能为空");
            return;
        }
        this.impl.removeValue(key);
    }

    private _impl: IStorage;
    private get impl(): IStorage {
        if (this._impl == null) {
            this._impl = Injector.getInject(Storage.KEY);
        }
        if (this._impl == null) {
            throw new Error("未注入：" + Storage.KEY);
        }
        return this._impl;
    }
}